﻿/**************************************************************
 *
 * 唯一标识：4527e7fd-7be6-4db1-be23-48709c098faa
 * 命名空间：Sgr.Indentity.Utilities
 * 描述：简化版验证码生成器（纯色或浅渐变背景 + 少量噪声线/点 + 轻微字符抖动），突出可读性
 *
 **************************************************************/

using Sgr.Utilities;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System.Numerics;

namespace Sgr.Indentity.Utilities
{
    public static class ImageSharpCaptchaHelper
    {
        public static (string code, byte[] image) CreateCaptcha(int length = 4, bool useNum = true, bool useLetter = true)
        {
            var code = RandomHelper.GetRandomString(length, useNum, false, useLetter, false);
            return CreateCaptchaCode(code);
        }

        public static string BuildCaptchaCode(string code)
        {
            return HashHelper.CreateMd5($"sgr-{code.ToLower()}-captcha-{DateTime.UtcNow.ToShortDateString()}");
        }

        public static (string code, byte[] image) CreateArithmeticCaptcha()
        {
            char[] operators = { '+', '-' };
            int first = RandomHelper.GetRandom(10, 99);
            int second = RandomHelper.GetRandom(10, 99);
            char op = operators[RandomHelper.GetRandom(0, operators.Length)];
            if (op == '-' && first < second)
                (first, second) = (second, first);

            int value = op == '+' ? first + second : first - second;
            string expr = $"{first}{op}{second}=?";
            var (_, imgBytes) = CreateCaptchaCode(expr);
            return (value.ToString(), imgBytes);
        }

        private static (string code, byte[] image) CreateCaptchaCode(string code)
        {
            const int width = 150;
            const int height = 50;

            using var image = new Image<Rgba32>(width, height);

            var bg1 = PastelColor(200, 255);
            var bg2 = PastelColor(180, 240);
            image.Mutate(ctx =>
            {
                ctx.Fill(new LinearGradientBrush(
                    new PointF(0, 0),
                    new PointF(width, height),
                    GradientRepetitionMode.None,
                    new[]
                    {
                        new ColorStop(0, bg1),
                        new ColorStop(1, bg2)
                    }));
            });

            AddLightNoise(image, width, height);
            DrawClearText(image, code, width, height);

            using var ms = new MemoryStream();
            try
            {
                var encoder = new WebpEncoder
                {
                    FileFormat = WebpFileFormatType.Lossy,
                    Quality = 85
                };
                image.Save(ms, encoder);
            }
            catch
            {
                ms.Position = 0;
                ms.SetLength(0);
                image.SaveAsPng(ms);
            }

            return (code, ms.ToArray());
        }

        private static void DrawClearText(Image<Rgba32> image, string code, int width, int height)
        {
            var family = SystemFonts.TryGet("Arial", out var arial) ? arial : SystemFonts.Collection.Families.First();

            // 简化：直接用稍微小一点的字号，避免左右贴边
            float fontSize = height * 0.7f;          // 原 0.7f -> 0.62f
            float charSpacing = 6f;                   // 固定间距（原依赖字号 0.05f）
            int horizontalPadding = 10;               // 固定左右留白

            // 简化：估算字符宽度比例调小让整体更窄
            float estCharWidth = fontSize * 0.55f;     // 原 0.62f -> 0.55f

            // 用剩余宽度（扣除左右留白）来判断是否需要再缩放字号
            float availableWidth = width - horizontalPadding * 2;
            float totalWidth = code.Length * estCharWidth + (code.Length - 1) * charSpacing;

            if (totalWidth > availableWidth)
            {
                // 按比例整体缩放（非常简单，不再循环）
                float scale = availableWidth / totalWidth;
                fontSize *= scale;
                estCharWidth *= scale;
            }

            float startX = (width - (code.Length * estCharWidth + (code.Length - 1) * charSpacing)) / 2f;
            float baseY = height / 2f;

            var font = family.CreateFont(fontSize, FontStyle.Bold);

            image.Mutate(ctx =>
            {
                for (int i = 0; i < code.Length; i++)
                {
                    char ch = code[i];
                    float x = startX + i * (estCharWidth + charSpacing);
                    float y = baseY + RandomHelper.GetRandom(-3, 4); // 轻微上下抖动

                    float angleDeg = RandomHelper.GetRandom(-8, 9);  // 小角度
                    float angleRad = angleDeg * (float)Math.PI / 180f;

                    var color = new Color(VividReadableColor());
                    var origin = new Vector2(x, y);
                    var transform = Matrix3x2.CreateRotation(angleRad, origin);
                    ctx.SetDrawingTransform(transform);

                    ctx.DrawText(ch.ToString(), font, color, new PointF(x, y - fontSize * 0.58f));

                    ctx.SetDrawingTransform(Matrix3x2.Identity);
                }
            });
        }

        private static void AddLightNoise(Image<Rgba32> image, int width, int height)
        {
            int lineCount = (int)(width * height * 0.002);
            int pointCount = (int)(width * height * 0.02);

            image.Mutate(ctx =>
            {
                for (int i = 0; i < lineCount; i++)
                {
                    var c = PastelColor(160, 220).WithAlpha(0.8f);
                    var p1 = new PointF(RandomHelper.GetRandom(width), RandomHelper.GetRandom(height));
                    var p2 = new PointF(RandomHelper.GetRandom(width), RandomHelper.GetRandom(height));
                    ctx.DrawLine(c, 1, p1, p2);
                }
            });

            for (int i = 0; i < pointCount; i++)
            {
                int x = RandomHelper.GetRandom(width);
                int y = RandomHelper.GetRandom(height);
                var c = PastelColor(150, 230);
                // Color 没有直接 R/G/B 属性，需要先转换成具体像素类型
                var rgba = c.ToPixel<Rgba32>();
                image[x, y] = new Rgba32(rgba.R, rgba.G, rgba.B, 255);
            }
        }

        private static Color PastelColor(int min, int max)
        {
            byte r = (byte)RandomHelper.GetRandom(min, max);
            byte g = (byte)RandomHelper.GetRandom(min, max);
            byte b = (byte)RandomHelper.GetRandom(min, max);
            return new Color(new Rgba32(r, g, b, 255));
        }

        private static Rgba32 VividReadableColor()
        {
            bool dark = RandomHelper.GetRandom(0, 2) == 0;
            if (dark)
            {
                byte r = (byte)RandomHelper.GetRandom(20, 80);
                byte g = (byte)RandomHelper.GetRandom(20, 80);
                byte b = (byte)RandomHelper.GetRandom(20, 80);
                return new Rgba32(r, g, b, 255);
            }
            else
            {
                byte r = (byte)RandomHelper.GetRandom(120, 255);
                byte g = (byte)RandomHelper.GetRandom(60, 200);
                byte b = (byte)RandomHelper.GetRandom(60, 200);
                return new Rgba32(r, g, b, 255);
            }
        }
    }
}